<?php

namespace App\Services\IdentityOcr\Drivers;

use App\Services\IdentityOcr\IdentityOcrResult;
use App\Services\IdentityOcr\IdentityOcrVerifier;
use com\junziqian\sdk\util\RequestUtils;
use Illuminate\Support\Facades\Log;
use RuntimeException;
use Throwable;

class JunziqianIdentityOcrVerifier implements IdentityOcrVerifier
{
    protected array $config;

    public function __construct(array $config)
    {
        $this->config = $config;
    }

    public function recognize(string $imagePath): IdentityOcrResult
    {
        $this->ensureConfigured();

        $payload = [
            'file' => new \CURLFile($imagePath),
        ];

        Log::info('[IdentityOCR][Junziqian] 请求参数', [
            'endpoint' => $this->config['service_url'] ?? null,
            'path' => $imagePath,
        ]);

        try {
            $client = $this->createClient();
            $path = $this->config['path'] ?? '/v2/ocr/ocrIdentity';
            $response = $client->doPost($path, $payload);
        } catch (Throwable $e) {
            Log::error('[IdentityOCR][Junziqian] 请求异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);
            return IdentityOcrResult::failure('身份证识别供应商请求异常', null, [
                'path' => $imagePath,
                'exception' => [
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                ],
            ]);
        }

        $responseArray = $this->normalizeResponse($response);

        Log::info('[IdentityOCR][Junziqian] 返回结果', [
            'response' => $responseArray,
        ]);

        if (($responseArray['success'] ?? false) === true) {
            $data = $responseArray['data'] ?? [];

            return IdentityOcrResult::success([
                'name' => $data['name'] ?? '',
                'idNumber' => $data['idNo'] ?? '',
                'gender' => $data['gender'] ?? '',
                'address' => $data['address'] ?? '',
                'nation' => $data['nation'] ?? '',
                'birthday' => $data['birthday'] ?? '',
                'orderNo' => $data['orderNo'] ?? '',
            ], $data['resultMessage'] ?? '识别成功', [
                'response' => $responseArray,
            ]);
        }

        $message = (string) ($responseArray['message'] ?? $responseArray['msg'] ?? '识别失败');
        $code = (string) ($responseArray['code'] ?? null);

        return IdentityOcrResult::failure($message, $code, [
            'response' => $responseArray,
        ]);
    }

    public function recognizeWithIdentity(
        string $fullName,
        string $identityCard,
        string $frontImagePath,
        string $backImagePath
    ): IdentityOcrResult {
        $this->ensureConfigured();

        $payload = [
            'fullName' => $fullName,
            'identityCard' => $identityCard,
            'idenFront' => new \CURLFile($frontImagePath),
            'idenReverse' => new \CURLFile($backImagePath),
        ];

        Log::info('[IdentityOCR][Junziqian] 云证书识别请求', [
            'endpoint' => $this->config['service_url'] ?? null,
            'fullName' => $fullName,
            'identityCard' => $identityCard,
        ]);

        try {
            $client = $this->createClient();
            $path = '/v2/user/cloudCertiPerInfo';
            $response = $client->doPost($path, $payload);
        } catch (Throwable $e) {
            Log::error('[IdentityCA][Junziqian] 云证书上传异常', [
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString(),
            ]);

            return IdentityOcrResult::failure('身份证识别供应商请求异常', null, [
                'request' => [
                    'fullName' => $fullName,
                    'identityCard' => $identityCard,
                ],
                'exception' => [
                    'message' => $e->getMessage(),
                    'file' => $e->getFile(),
                    'line' => $e->getLine(),
                ],
            ]);
        }

        $responseArray = $this->normalizeResponse($response);

        Log::info('[IdentityCA][Junziqian] 云证书识别返回', [
            'response' => $responseArray,
        ]);

        if (($responseArray['success'] ?? false) === true) {
            $data = $responseArray['data'] ?? [];

            return IdentityOcrResult::success([
                'name' => $data['name'] ?? $fullName,
                'idNumber' => $data['identityCard'] ?? $identityCard,
                'gender' => $data['gender'] ?? '',
                'address' => $data['address'] ?? '',
                'nation' => $data['nation'] ?? '',
                'birthday' => $data['birthday'] ?? '',
                'orderNo' => $data['orderNo'] ?? '',
            ], $data['resultMessage'] ?? '上传成功', [
                'response' => $responseArray,
            ]);
        }

        $message = (string) ($responseArray['message'] ?? $responseArray['msg'] ?? '识别失败');
        $code = (string) ($responseArray['code'] ?? null);

        return IdentityOcrResult::failure($message, $code, [
            'response' => $responseArray,
        ]);
    }

    protected function ensureConfigured(): void
    {
        foreach (['service_url', 'app_key', 'app_secret'] as $key) {
            if (empty($this->config[$key])) {
                throw new RuntimeException(sprintf('身份证识别 Junziqian 驱动缺少配置项 [%s]', $key));
            }
        }
    }

    protected function createClient(): RequestUtils
    {
        $serviceUrl = rtrim($this->config['service_url'], '/');
        $appKey = $this->config['app_key'];
        $appSecret = $this->config['app_secret'];
        $encryMethod = $this->config['encry_method'] ?? null;
        $tsType = $this->config['ts_type'] ?? 2;

        return new RequestUtils($serviceUrl, $appKey, $appSecret, $encryMethod, $tsType);
    }

    protected function normalizeResponse($response): array
    {
        if (is_array($response)) {
            return $response;
        }

        if (is_object($response)) {
            return json_decode(json_encode($response), true) ?: [];
        }

        return [];
    }
}
